package com.expert.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.expert.Mapper.MenuMapper;
import com.expert.Mapper.RoleMapper;
import com.expert.Mapper.UserMapper;
import com.expert.constant.RedisKeyConstant;
import com.expert.context.BaseContext;
import com.expert.dto.AddMenuDTO;
import com.expert.dto.UpdateMenuDTO;
import com.expert.exception.DeleteException;
import com.expert.exception.UpdateException;
import com.expert.pojo.Menu;
import com.expert.pojo.Role;
import com.expert.pojo.RoleMenu;
import com.expert.service.MenuService;
import com.expert.service.RoleMenuService;
import com.expert.util.MenuTreeUtil;
import com.expert.vo.MenuVo;
import com.expert.vo.ParentMenuVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @ClassName: MenuServiceImpl
 * @Author: cxs
 * @Date: 2024/01/24 13:48
 * @Description:
 **/

@Service
@Slf4j
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
    @Autowired
    UserMapper userMapper;
    @Autowired
    RoleMapper roleMapper;
    @Autowired
    RoleMenuService roleMenuService;
    @Autowired
    RedisTemplate<String, List<MenuVo>> redisTemplate;
    //创建菜单
    @Override
    public List<MenuVo> createMenu() {
        //1.获取菜单id
        Long userId = BaseContext.getCurrentId();
        Long role = userMapper.selectById(userId).getRole();
        //首先在redis中查找缓存，找到直接返回
        List<MenuVo> menuVoCache = redisTemplate.opsForValue().get(RedisKeyConstant.SYSTEM_MENU_CACHE + role);
        if (menuVoCache == null) {
            log.info("菜单缓存未命中。");
            List<RoleMenu> roleMenus = this.roleMenuService.lambdaQuery().eq(RoleMenu::getRoleId, role).list();
            List<Long> menuIds = roleMenus.stream().map(RoleMenu::getMenuId).toList();
            List<Menu> menuList = this.lambdaQuery().in(Menu::getId, menuIds).orderByAsc(Menu::getId).list();
            List<MenuVo> menuVoList = new ArrayList<>();
            for (Menu menu : menuList) {
                MenuVo menuVo = new MenuVo();
                BeanUtils.copyProperties(menu, menuVo);
                menuVoList.add(menuVo);
            }
            List<MenuVo> menuTree = new ArrayList<>();
            if (menuVoList.size() > 0) {
                menuTree = MenuTreeUtil.buildDeptTreeByStream(menuVoList);
            }
            //存入redis中
            redisTemplate.opsForValue().set(RedisKeyConstant.SYSTEM_MENU_CACHE + role, menuTree);
            return menuTree;
        } else {
            log.debug(menuVoCache.toString());
            return menuVoCache;
        }

    }

    /**
     * 分页查询菜单信息
     *
     * @param page     当前页
     * @param pageSize 每页条数
     * @param title    标题
     * @param pTitle   父级标题
     * @return 分页查询结果
     */
    @Override
    public Page<Menu> pageMenu(Integer page, Integer pageSize, String title, String pTitle) {
        //初始数据处理
        Page<Menu> menuPage = new Page<>(page, pageSize);

        page(menuPage,new LambdaQueryWrapper<Menu>()
                .like(StringUtils.isNotEmpty(title),Menu::getTitle,title)
                .like(StringUtils.isNotEmpty(pTitle),Menu::getPtitle,pTitle)
                .orderByAsc(Menu::getPid)
                .orderByAsc(Menu::getId));
        return menuPage;
    }

    /**
     * 获取系统所有菜单信息
     *
     * @return 菜单列表
     */
    @Override
    public List<MenuVo> getSystemMenus() {
        List<Menu> menuList = this.lambdaQuery().orderByAsc(Menu::getId).list();
        //构建vo
        List<MenuVo> menuVoList = menuList.stream().map(item -> {
            MenuVo menuVo = new MenuVo();
            BeanUtils.copyProperties(item, menuVo);
            return menuVo;
        }).toList();
        List<MenuVo> menuTree=new ArrayList<>();
        if (menuVoList.size()>0){
            menuTree=MenuTreeUtil.buildDeptTreeByStream(menuVoList);
        }
        return menuTree;
    }

    /**
     * 获取父级菜单信息
     *
     * @return
     */
    @Override
    public List<ParentMenuVo> getParentMenu() {
        List<Menu> menuList = this.lambdaQuery().eq(Menu::getPid,0L) .list();
        List<ParentMenuVo> parentMenus = menuList.stream().map(menu -> {
            ParentMenuVo parentMenuVo = new ParentMenuVo();
            BeanUtils.copyProperties(menu, parentMenuVo);
            return parentMenuVo;
        }).toList();
        return parentMenus;
    }

    /**
     * 添加菜单信息
     *
     * @param addMenuDTO
     * @return
     */
    @Override
    public void addMenu(AddMenuDTO addMenuDTO) {
        Menu menu=new Menu();
        BeanUtils.copyProperties(addMenuDTO,menu);
        if (addMenuDTO.getParent()!=null) {
            System.out.println(addMenuDTO);
            Long parentId = addMenuDTO.getParent();
            Menu parentMenu = this.lambdaQuery().eq(Menu::getId, parentId).one();
            menu.setPid(parentMenu.getId());
            menu.setPtitle(parentMenu.getTitle());
        }else {
            menu.setPid(0L);
            menu.setPtitle(null);
        }
        this.save(menu);
    }

    /**
     * 删除菜单信息
     *
     * @param ids
     */
    @Override
    @Transactional
    public void deleteMenu(ArrayList<Long> ids) {

        ids.forEach(id->{
            Long count = this.roleMenuService.lambdaQuery().eq(RoleMenu::getMenuId, id).count();
            System.out.println(this.roleMenuService.lambdaQuery().eq(RoleMenu::getMenuId, id).list());
            if (count>0){
                throw  new DeleteException("菜单已被使用，删除失败！");
            }
        });
        this.removeBatchByIds(ids);
    }

    /**
     * 修改菜单信息
     *
     */
    @Override
    public void updateMenu(UpdateMenuDTO updateMenuDTO) {
        if (updateMenuDTO.getId()==null||updateMenuDTO.getPath()==null||updateMenuDTO.getTitle()==null||updateMenuDTO.getIcon()==null){
            throw  new UpdateException("存在为空的内容，修改失败!");
        }
        Menu menu = this.lambdaQuery().eq(Menu::getId, updateMenuDTO.getId()).one();
        BeanUtils.copyProperties(updateMenuDTO,menu);
        Set<String> keys = redisTemplate.keys(RedisKeyConstant.SYSTEM_MENU_CACHE + "*");
        assert keys != null;
        redisTemplate.delete(keys);
        this.updateById(menu);
    }
}
